package.path = "lualib/?.lua;server_websocket/?.lua" 
local MJLogic = {}
local table_insert = table.insert
local table_remove = table.remove

-- 统计
MJLogic.HS_ZIMO						= 1		-- 自摸(小胡)
MJLogic.HS_JIEPAO					= 2		-- 自摸(小胡)
MJLogic.HS_DIANPAO					= 3		-- 自摸(小胡)
MJLogic.HS_MINGGANG					= 4		-- 自摸(小胡)
MJLogic.HS_ANGANG					= 5		-- 自摸(小胡)

-- 牌型
MJLogic.CT_WANZI                    = 0x00      --  万子
MJLogic.CT_TONGZI                   = 0x10      --  同子
MJLogic.CT_SUOZI                    = 0x20      --  索子
MJLogic.CT_FENGPAI                  = 0x30      --  风牌
MJLogic.CT_JIANPAI                  = 0x40      --  箭牌
MJLogic.CT_HUAPAI                   = 0x50      --  花牌

-- 胡牌
MJLogic.HU_NONE                     = 0         -- 没有胡
MJLogic.HU_JIHU						= 1			-- 平胡
MJLogic.HU_QIANGGANG				= 2			-- 抢杠
MJLogic.HU_GANGKAI					= 3			-- 杠开
MJLogic.HU_SSL						= 4			-- 十三烂
MJLogic.HU_QXSSL					= 5			-- 7星十三烂
MJLogic.HU_DD						= 6			-- 单钓
MJLogic.HU_DQD						= 7			-- 大7
MJLogic.HU_QYSDQD					= 8			-- 清一色大7对
MJLogic.HU_XQD						= 9			-- 小7对
MJLogic.HU_QYSXQD					= 10		-- 清一色小七
MJLogic.HU_HHXQD					= 11		-- 单豪华小七对
MJLogic.HU_HHXQD2					= 12		-- 双豪华小七对
MJLogic.HU_HHXQD3					= 13		-- 三豪华小七对
MJLogic.HU_DDC						= 14		-- 大吊车	除了单钓的牌外，其他牌都已经碰 
MJLogic.HU_QYS						= 15		-- 清一色	
MJLogic.HU_ZYS						= 16		-- 字一色	
MJLogic.HU_QZH						= 17		-- 边/卡(音qiā、ka)张胡	
MJLogic.HU_HDZM						= 18		-- 海底自摸
MJLogic.HU_QYSDD					= 19		-- 清一色 单钓
MJLogic.HU_QYSQZH					= 20		-- 清一色 边/卡(音qiā、ka)张胡	
MJLogic.HU_TIANHU		= 31 -- 天胡
MJLogic.HU_DIHU			= 32 -- 地胡

MJLogic.HU_GANG_FANG		= 94 -- 放杠
MJLogic.HU_GANG_JIE		= 95 -- 接杠
MJLogic.HU_GANG_GONG			= 96 -- 公杠
MJLogic.HU_GANG_AN			= 97 -- 暗杠
MJLogic.HU_GANG_SHANG_PAO			= 98 -- 杠上炮
MJLogic.ZHUI_ZHUANG			= 99 -- 跟拍追庄


MJLogic.HUSCORES = {
	[ MJLogic.HU_NONE		] = 0, 
	[ MJLogic.HU_JIHU		] = 1, 
	[ MJLogic.HU_QIANGGANG	] = 2, 
	[ MJLogic.HU_GANGKAI	] = 2, --杠开 所胡牌型算分后再翻2倍
	[ MJLogic.HU_SSL		] = 2, 
	[ MJLogic.HU_QXSSL		] = 4, 
	[ MJLogic.HU_DD			] = 2, 
	[ MJLogic.HU_DQD		] = 3, 
	[ MJLogic.HU_QYSDQD		] = 15, 
	[ MJLogic.HU_XQD		] = 5, 
	[ MJLogic.HU_QYSXQD		] = 25, -- 清一色小七
	[ MJLogic.HU_HHXQD		] = 10, 
	[ MJLogic.HU_HHXQD2		] = 20, 
	[ MJLogic.HU_HHXQD3		] = 40, 
	[ MJLogic.HU_DDC		] = 6,  --.大吊车
	[ MJLogic.HU_QYS		] = 5, 
	[ MJLogic.HU_ZYS		] = 5, 
	[ MJLogic.HU_QZH		] = 2, 
	[ MJLogic.HU_HDZM		] = 2, --海底自摸 所胡牌型算分后再翻2倍
	[ MJLogic.HU_QYSDD		] = 10, --清一色 单钓
	[ MJLogic.HU_QYSQZH		] = 10, --清一色 边/卡(音qiā、ka)张胡	
	[ MJLogic.HU_TIANHU		] = 10, --天胡	
	[ MJLogic.HU_DIHU		] = 10, --地胡	
	
	[ MJLogic.HU_GANG_SHANG_PAO		] = 2, --杠上炮	
	[ MJLogic.HU_GANG_JIE		] = 1, --放杠	
	[ MJLogic.HU_GANG_FANG		] = 1, --放杠	
	[ MJLogic.HU_GANG_GONG		] = 1, --公杠	
	[ MJLogic.HU_GANG_AN		] = 1, --暗杠	
	[ MJLogic.ZHUI_ZHUANG		] = 1, --跟拍追庄	 
}

MJLogic.MA_JIANG_CARD = {
    0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,                       --万子  
  -- 17 ,18,  19,  20,  21,  22,  23,  24,  25	
    0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,                       --同子   
	-- 33 ,34,  35,  36,  37,  38,  39,  40,  41	
    0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,                       --索子   
	
	0x31,0x32,0x33,0x34,                                                --风牌(东南西北) 
    0x41,0x42,0x43,                                                     --箭牌(中发白) 
}

function MJLogic.print_cards(arr)
    for i,v in MJLogic.pairsByKeys(arr) do
        if v > 0 then
            print(string.format("0x%02x   %d",i, v))
        end
        --print(string.format("0x%02x   %d",i, v))
    end
end

function clone_table(object)
    local lookup_table = {}
    local function _copy(object)
        if type(object) ~= "table" then
            return object
        elseif lookup_table[object] then
            return lookup_table[object]
        end
        local new_table = {}
        lookup_table[object] = new_table
        for key, value in pairs(object) do
            new_table[_copy(key)] = _copy(value)
        end
        return setmetatable(new_table, getmetatable(object))
    end
    return _copy(object)
end
function MJLogic.in_array(arr, obj)
	for i, v in ipairs(arr) do
		if v == obj then return true end
	end
	return false
end

function MJLogic.not_in_insert_array(arr, obj)
	for i, v in ipairs(arr) do
		if v == obj then return end
	end
	table.insert(arr,obj)
end


function MJLogic.NextCard(card)
	local color = MJLogic.GetColor(card)
	local value = MJLogic.GetValue(card)
	local next_value = 0
	if color == 0 or color == 16 or color == 32 then
		next_value = (value == 9 and 1 or value + 1)
	elseif color == 48 then
		next_value = (value == 4 and 1 or value + 1)
	elseif color == 64 then
		next_value = (value == 3 and 1 or value + 1)
	end
	return tonumber(color + next_value)
end

function MJLogic.PrevCard(card)
	local color = MJLogic.GetColor(card)
	local value = MJLogic.GetValue(card)
	local next_value = 0
	if color == 0 or color == 16 or color == 32 then
		next_value = (value == 1 and 9 or value - 1)
	elseif color == 48 then
		next_value = (value == 1 and 4 or value - 1)
	elseif color == 64 then
		next_value = (value == 1 and 3 or value - 1)
	end
	return tonumber(color + next_value)
end

-- 返回一个顺序的迭代器
-- 输入: 统计牌数的表
function MJLogic.pairsByKeys(t) 
    local a = {} 
    for n in pairs(t) do 
        a[#a+1] = n 
    end 
    table.sort(a) 
    local i = 0 
    return function() 
        i = i + 1 
        return a[i], t[a[i]] 
    end 
end

function MJLogic.has_card(cards, tbl)
    local count = 0
    local data = {}
    for k,v in ipairs(tbl) do
        if not data[v] then
            data[v] = 0
        end
        data[v] = data[v] + 1
        count = count + 1
    end

    for i = #cards, 1, -1 do
        local v = cards[i]
        if data[v] and data[v] > 0 then
            data[v] = data[v] - 1
            count = count - 1
        end
    end
    return count == 0
end

function MJLogic.delete_card(cards, tbl)
    local remove = {}
    for k,v in ipairs(tbl) do
        if not remove[v] then
            remove[v] = 0
        end
        remove[v] = remove[v] + 1
    end

    for i = #cards, 1, -1 do
        local v = cards[i]
        if remove[v] and remove[v] > 0 then
            table_remove(cards, i)
            remove[v] = remove[v] - 1
        end
    end
end

function MJLogic.delete_by_card(cards, card)
	for i = #cards, 1, -1 do
        local v = cards[i]
        if v == card then
            table_remove(cards, i)
        end
    end
end

function MJLogic.sortASCE( t )
    table.sort(t)
end

-- 获取花式
function MJLogic.GetColor( data )
    --return cc_math:bit_and(data, 0xF0)
    return data & 0xF0
end

-- 获取数值
function MJLogic.GetValue( data )
    --return cc_math:bit_and(data, 0x0F)
    return data & 0x0F
end

function MJLogic.Shaizi()
	local shaizi = {}
	shaizi[1] = math.random(1, 6)
	shaizi[2] = math.random(7, 12) - 6
	return shaizi
end

-- 判断剩余牌的数量
function MJLogic.RemainCard(arr)
    local sum = 0
    if arr ~= {} then
	    for i,v in pairs(arr) do
	        sum = sum + v
	    end
    end
    return sum
end

-- 统计手牌的各个牌的数量
function MJLogic.GetHandCount( data )
    local hand_count = {}
    for i,v in ipairs(data) do
        if hand_count[v] == nil then
            hand_count[v] = 1
        else
            hand_count[v] = hand_count[v] + 1
        end
    end
    return hand_count
end

function MJLogic.has_card_num(cards, card)
	local count = 0
	for i = #cards, 1, -1 do
        local v = cards[i]
        if v == card then
            count = count + 1
        end
    end
	return count
end

-- 统计手上牌的颜色数量
function MJLogic.GetHandColor( data) 
	local color_count = {}
	local count = 0
	for i,v in ipairs(data) do
		local color = MJLogic.GetColor(v)
		if color_count[color] == nil then
			color_count[color] = 1
			count = count + 1
		else
			color_count[color] = color_count[color] + 1
		end
	end
	return count,color_count
end


-- 获取所有对子
function MJLogic.GetDuizi(data)
    local duizi = {}
    local hand_count = MJLogic.GetHandCount(data)
    for i, num in MJLogic.pairsByKeys(hand_count) do
        if num >= 2 and num < 4 then
            table.insert(duizi, i)
        elseif num == 4 then
            table.insert(duizi, i)
            table.insert(duizi, i)
        end
    end
    return duizi
end

-- 手上的杠牌
function MJLogic.GetGangPai(hand)
    local gangs = {}
    local hand_count = MJLogic.GetHandCount(hand)
    for i, num in MJLogic.pairsByKeys(hand_count) do
        if num == 4 then
            table.insert(gangs, i)
        end
    end
    return gangs
end


-- 明杠
function MJLogic.GetGroupGangpai(hand,group)
	for i,card in ipairs(hand) do
		for j,g in ipairs(group) do
			if card == g[1] and card == g[2] and card == g[3] then
				return card
			end
		end
	end	
	return 0
end


function MJLogic.GetCanGang(hand,group,cant_gang_cards)
	local gang_data = MJLogic.GetGangPai(hand)
	if #gang_data > 0 then
		return gang_data[1],1
	end
	-- 手中的每个牌跟group判断	
	local gang_card = MJLogic.GetGroupGangpai(hand,group, cant_gang_cards)
	if gang_card > 0 then
		for i,v in ipairs(cant_gang_cards) do 
			if v == gang_card then 
				return nil,0
			end
		end
		return gang_card,3
	end
	return nil,0
end

-- 判断是否可以吃牌(组成顺子)
function MJLogic.CanChi( data, card, ret)
    if ret == nil then
        ret = {}
    end
    if card >= 0x31 then
        return false
    end
    local hand_count = MJLogic.GetHandCount(data)
	if hand_count[card-2] and hand_count[card-1] then
		table.insert(ret, {card-2,card,card-1})
	end
	if hand_count[card-1] and hand_count[card+1] then
		table.insert(ret, {card-1, card, card+1})
	end
	if hand_count[card+1] and hand_count[card+2] then
		table.insert(ret, {card+1, card, card+2})
	end
	
    if #ret > 0 then
        return true
    end
    return false
end




-- 判断是否可以碰
function MJLogic.CanPeng(data, cant_peng_cards, out_card)
	
	if #cant_peng_cards > 0 then 
		for i,v in ipairs(cant_peng_cards) do 
			if v == out_card then 
				return false
			end
		end
	end
	
    local duizi = MJLogic.GetDuizi(data)
    for i,v in ipairs(duizi) do
        if v == out_card then
            return true
        end
    end
    return false
end

-- 判断是否可以杠
function MJLogic.CanGang(data, card)
    local hand_count = MJLogic.GetHandCount(data)
    for i, num in MJLogic.pairsByKeys(hand_count) do
        if i == card and num == 3 then
            return true
        end
    end
    return false
end
  
-- 判断自摸 hu_type_color 字一色 或者 清一色
function MJLogic.CanZimoHu( data, group_data, hu_card, game_type)
	local new_data = {} --clone(data)
	for i,v in ipairs(data) do 
		table.insert(new_data,v)
	end
	
	local new_data2 = {}
	for i,v in ipairs(group_data) do 
		table.insert(new_data2, v)
	end
	local rs,hu_type_color = MJLogic.JudgeHuType(new_data, new_data2, hu_card)
	return rs,hu_type_color
end
--game_type 为 0  不允许平湖   1 可以平湖  is_qianggang 1 为抢杠胡
function MJLogic.CanChiHu(data,group_data,hu_card,game_type,is_qianggang) 
	local new_data = {} --clone(data)
	for i,v in ipairs(data) do 
		table.insert(new_data,v)
	end
	
	local new_data2 = {}
	for i,v in ipairs(group_data) do 
		table.insert(new_data2, v)
	end
	
	table.insert(new_data,hu_card) 
	local rs,hu_type_color = MJLogic.JudgeHuType(new_data, new_data2, hu_card)
	if is_qianggang == 0 and game_type == 0 and rs == MJLogic.HU_JIHU and hu_type_color == 0 then
		rs = MJLogic.HU_NONE
	end 
	return rs,hu_type_color
end


function MJLogic.JudgeHu_Duidui( arr )
	local kuan = 0
	local function DuiDui()
		if MJLogic.RemainCard(arr) == 0 then return 1 end
    	for i,num in pairs(arr) do
			if num > 0 then
				if num == 1 then --牌只有一个 直接退出
					return 0
				end 
				if num >= 2 then
					arr[i] = arr[i] - 2  
					kuan = num > 2 and kuan + 1 or kuan	
					if DuiDui() == 1 then return 1 end 
					arr[i] = arr[i] + 2  
					kuan = num > 2 and kuan - 1 or kuan
				end 
			end
		end
		return 0
	end
	
	if DuiDui() == 1 then
		if kuan == 1 then 
			return MJLogic.HU_HHXQD
		elseif kuan == 2 then 
			return MJLogic.HU_HHXQD2
		elseif kuan == 3 then 
			return MJLogic.HU_HHXQD3
		end
		 
		return MJLogic.HU_XQD
	else
		return MJLogic.HU_NONE
	end
end

--大7对
function MJLogic.JudgeHu_PENGPENGHU(arr,   group) 
	local pnum = 0  
	local is_angang = 0  
	if group and #group > 0 then
		for i,v in ipairs(group) do
			if v[1] ~= v[2] or v[1] ~= v[3] then
				return MJLogic.HU_NONE
			end  
			if v[5] ~= nil and v[5] == 2 then
				is_angang = 1
			end
			pnum = pnum + 1
		end
	end 
	 
	if  is_angang == 0 and pnum == 4 then --不能有暗杠
		return MJLogic.HU_DDC 
	end 

	local jiang = 0  
    for i, num in pairs(arr) do  
		if num == 1 or num == 4 then
			return MJLogic.HU_NONE
		end 
		if num ~= 3 and jiang == 1 then
			return MJLogic.HU_NONE
		end 
		if num == 2 and jiang == 0 then
			jiang = 1   
		end 
	end 

	--HU_DQD = 7 大7对
	return MJLogic.HU_DQD
end


function MJLogic.JudgeHu_Other(data, hu_card)
	
	local hu_type,comps = MJLogic.JudgeHu_Normal( data, noshunzi, hu_card)
	if hu_type == MJLogic.HU_NONE then return hu_type end 
 
	if hu_type > 0 then return  hu_type end  
	return MJLogic.HU_NONE
end

-- 十三烂
function MJLogic.JudgeHu_SSY(data)  
	local arr = {}
    for i,v in ipairs(MJLogic.MA_JIANG_CARD) do
        arr[v] = 0
    end
    for i,v in ipairs(data) do
		arr[v] = arr[v] + 1
    end
	
	local zi_num = 0  
    for i, num in pairs(arr) do
		if num > 0 then 
			if num >= 2 then return MJLogic.HU_NONE end
			if i >= 0x31 then
				zi_num = zi_num + 1	
			else
				local value = MJLogic.GetValue(i)
				if value < 8 and (arr[i+1] > 0 or arr[i+2] > 0) then
					return 	MJLogic.HU_NONE
				elseif value == 8 and arr[i+1]> 0 then
					return 	MJLogic.HU_NONE
				end
			end 
		end
    end
	
	if zi_num >= 7 then
		return MJLogic.HU_QXSSL
	else
		return MJLogic.HU_SSL
	end
end


function MJLogic.JudgeHuType(data, group, hu_card) 
	local hu_type = MJLogic.HU_NONE

	local arr = {} 
	local colors = {} 
	local is_two = 0
	local is_zi = 1
	for i,v in ipairs(data) do 
		local tmp = MJLogic.GetColor(v)
		MJLogic.not_in_insert_array(colors,tmp)
		arr[v] = arr[v] and arr[v] + 1 or 1
		if arr[v] > 1 then
			is_two = 1
		end          
		if v < 0x31 then
			is_zi = 0
		end                                                                                  
	end	 
	for i,v in pairs(group) do 
		for ii,vv in pairs(v) do 
			if ii < 4 then -- {data[1],data[1],data[1],data[1],2})
				if #colors == 1 then  --增加 清一色判断
					local tmp = MJLogic.GetColor(vv)
					MJLogic.not_in_insert_array(colors,tmp)                                                                 
				end	      
				if is_zi == 1 and vv < 0x31 then
					is_zi = 0
				end   
			end   
		end	 
	end	 

	local hu_type_color = 0 -- 字一色 或者 清一色
	if #colors == 1 then --字一色
		hu_type_color = MJLogic.HU_QYS 
	end
	if is_zi == 1 then --字一色
		hu_type_color = MJLogic.HU_ZYS 
	end

	if #group == 0 then --有碰牌 或者杠牌 不可能是 7对 或者 十三烂
		if is_two == 0 then
			hu_type = MJLogic.JudgeHu_SSY(data)
		    if hu_type > 0 then return hu_type,hu_type_color end
		else 
			hu_type = MJLogic.JudgeHu_Duidui(arr) 
			if hu_type > 0 then return  hu_type,hu_type_color end 
		end 
	end
	if is_two == 1 then
		hu_type = MJLogic.JudgeHu_PENGPENGHU(arr, group)  
		if hu_type > 0 then return  hu_type,hu_type_color end
	end
	 
	if hu_type_color == MJLogic.HU_ZYS and hu_type == MJLogic.HU_NONE then
		hu_type = MJLogic.HU_ZYS
		hu_type_color = 0
		return hu_type,hu_type_color
	end 

	hu_type = MJLogic.JudgeHu_Other(data,   hu_card) 
	if hu_type > 0 then return  hu_type,hu_type_color end 

	return hu_type,hu_type_color
end


-- 判断普通胡
--[[  
    data: 手上的牌
	zj: 主精
	fj: 副精
	noshunzi: 没有顺子(碰碰胡)
--]]  
function MJLogic.JudgeHu_Normal( data, noshunzi, hu_card)
    local arr_new = {} 
    local jiang = 0     -- 将牌(眼牌)
    local is_one_card = 0    
	local groups = {}
    local arr_ka = {} 
    for i,v in ipairs(MJLogic.MA_JIANG_CARD) do
        arr_new[v] = 0 
        arr_ka[v] = 0 
    end
    for i,v in ipairs(data) do
		arr_new[v] = arr_new[v] + 1 
		if v == hu_card and is_one_card == 0 then 
			is_one_card = 1
		elseif v == hu_card and is_one_card == 1 then 
			arr_ka[v] = arr_ka[v] + 1 
		elseif v ~= hu_card  then 
			arr_ka[v] = arr_ka[v] + 1 
		end 
    end 
    local function NormalHu() 
        if MJLogic.RemainCard(arr) == 0 then return 1 end   -- 递归退出条件：如果没有剩牌，则胡牌返回
        for i, num in MJLogic.pairsByKeys(arr) do
            if num > 0 then
                local value = MJLogic.GetValue(i)
				-- 刻子
				if arr[i] >= 3 then    
                    arr[i] = arr[i] - 3 
					table.insert(groups,{i,i,i})
                    if NormalHu() == 1 then return 1 end
					table.remove(groups)
                    arr[i] = arr[i] + 3  
                end
				
				-- 2张组合
                if jiang == 0 and arr[i] >= 2 then
					jiang = i
					arr[i] = arr[i] - 2  
					table.insert(groups,{i,i})
                    if NormalHu() == 1 then return 1 end
					table.remove(groups)
					arr[i] = arr[i] + 2  
					jiang = 0    
                end
				
                -- 顺牌组合
                if i < 0x31 and not noshunzi and value ~= 8 and value ~= 9 and arr[i+1] > 0 and arr[i+2] > 0 then
                    arr[i] = arr[i] - 1
                    arr[i+1] = arr[i+1] - 1
                    arr[i+2] = arr[i+2] - 1
					table.insert(groups,{i,i+1,i+2})
                    if NormalHu() == 1 then return 1 end
					table.remove(groups)
                    arr[i] = arr[i] + 1
                    arr[i+1] = arr[i+1] + 1
                    arr[i+2] = arr[i+2] + 1
                end

                return 0
            end
        end
    end
 	arr = clone_table(arr_new)
    if NormalHu() == 1 then 
		local is_ka = 1 --是否卡张
		local is_dd = 0 --是否单吊
    	local new_groups = clone_table(groups)
    	groups = {} 
	    for i,v in ipairs(MJLogic.MA_JIANG_CARD) do 
	    	if v ~= hu_card  then  
	    		arr_ka[v] = arr_ka[v] + 1
					arr = clone_table(arr_ka)
					groups = {}
					jiang = 0 
				if NormalHu() == 1 then  
					is_ka = 0 
					break
	    		end
	    		arr_ka[v] = arr_ka[v] - 1
	    	end
	    end   
	    if is_ka == 1 then
		    for i,v in pairs(new_groups) do 
		    	if #v == 2 then
					if  v[1] == hu_card  then
			    		is_dd = 1
		    		end 
		    	end 
		    end  
	    end  
	    if is_ka == 1 then return MJLogic.HU_QZH end
	    if is_dd == 1 then return MJLogic.HU_DD end 
        return MJLogic.HU_JIHU
    else
        return MJLogic.HU_NONE
    end
end

 -- local tmp = MJLogic.CanChiHu({1,2,2,2,3,3,4,17,18,19,20,21,22},{},2,1)
 --  print(tmp)

return MJLogic


 